using System;
using System.CodeDom .Compiler ;
using System.CodeDom;
using EnvDTE;
using Extensibility;
using System.Collections ;
using System.Text ;
using System.Xml ;
using System.Text .RegularExpressions ;
using System.IO;

namespace AopDotNet
{
	namespace CodeModelXMLTreeBuilder
	{
		/// <summary>
		/// Summary description for LanguageEngine.
		/// </summary>
		public class LanguageEngine
		{
			static public string [] KeywordsAndDelimetersInClassDeclarationWithBase(ICodeGenerator codeGen)
			{
				CodeTypeDeclaration t=new CodeTypeDeclaration ("theclass");
				t.IsClass =true;
				t.TypeAttributes=0;
				t.BaseTypes.Add ( "base1");
				t.Members .Add (new CodeSnippetTypeMember ("body"));
				StringBuilder strPattern=new StringBuilder(GenerateCodeFromType(t,codeGen));
				strPattern.Replace ("theclass"," ");
				strPattern.Replace ("base1"," ");
				strPattern.Replace ("body"," ");

				return Regex .Split (strPattern.ToString (),@"[\s]+");
			}

			/// <summary>
			///  gets the keyword (if any) that is used in implementing interface ex : implements
			/// </summary>
			/// <param name="codeGen"></param>
			/// <returns></returns>
			static public string KeywordInClassImplementInterface(ICodeGenerator codeGen)
			{
				if (d1!=true)
				{
						ArrayList keywords1=new ArrayList (KeywordsAndDelimetersInClassDeclarationWithBases (codeGen));
					ArrayList keywords2=new ArrayList (KeywordsAndDelimetersInClassDeclarationWithBase (codeGen));
					for (int i=0;i<keywords2.Count ;i++)
					{
						while(keywords1.Contains (keywords2[i]))
							keywords1.Remove (keywords2[i]);
					}
					//if (keywords1.Count ==1)
					if (keywords1.Count >0&&((string)keywords1[0]).Length >1)
						keywordClassImplementInterface= (string)keywords1[0];
					else
						keywordClassImplementInterface = "";

					d1=true;
					return keywordClassImplementInterface;
				}
				else 
					return keywordClassImplementInterface;
			

			}
			private static string keywordClassImplementInterface;
			private static bool d1;

			/// <summary>
			/// gets the keyword (if any) that is used in inheritance ex : inherits or extends
			/// </summary>
			/// <param name="codeGen"></param>
			/// <returns></returns>
			static public string KeywordInClassInheritClass(ICodeGenerator codeGen)
			{
				if (d2!=true)
				{
				ArrayList keywords1=new ArrayList (KeywordsAndDelimetersInClassDeclarationWithBase (codeGen));
				ArrayList keywords2=new ArrayList (KeywordsAndDelimetersInClassDeclarationWithoutBases (codeGen));
				for (int i=0;i<keywords2.Count ;i++)
				{
					while(keywords1.Contains (keywords2[i]))
						keywords1.Remove (keywords2[i]);
				}
				//if (keywords1.Count ==1)
				if (keywords1.Count >0&&((string)keywords1[0]).Length >1)
					keywordClassInheritClass= (string)keywords1[0];
				else
					keywordClassInheritClass="";
				d2=true;
				return keywordClassInheritClass;
				}
				else
					return keywordClassInheritClass;
		
			}
			private static string keywordClassInheritClass;
			private static bool d2;

			static public string [] KeywordsAndDelimetersInClassDeclarationWithBases(ICodeGenerator codeGen)
			{
				CodeTypeDeclaration t=new CodeTypeDeclaration ("theclass");
				t.IsClass =true;
				t.TypeAttributes=0;
				t.BaseTypes.Add ( "base1");
				t.BaseTypes.Add ( "base2");
				t.BaseTypes.Add ( "base3");
				t.Members .Add (new CodeSnippetTypeMember ("body"));
				StringBuilder strPattern=new StringBuilder(GenerateCodeFromType(t,codeGen));
				strPattern.Replace ("theclass"," ");
				strPattern.Replace ("base1"," ");
				strPattern.Replace ("base2"," ");
				strPattern.Replace ("base3"," ");
				strPattern.Replace ("body"," ");

				return Regex .Split (strPattern.ToString (),@"[\s]+");
			}
			static public string [] KeywordsAndDelimetersInClassDeclarationWithoutBases(ICodeGenerator codeGen)
			{
				CodeTypeDeclaration t=new CodeTypeDeclaration ("theclass");
				t.IsClass =true;
				t.TypeAttributes=0;
				t.Members .Add (new CodeSnippetTypeMember ("body"));
				StringBuilder strPattern=new StringBuilder(GenerateCodeFromType(t,codeGen));
				strPattern.Replace ("theclass"," ");
				strPattern.Replace ("body"," ");
			
				return Regex .Split (strPattern.ToString (),@"[\s]+");
			}


			/// <summary>
			/// Generates a class from the Type Declaration
			/// </summary>
			/// <param name="t"></param>
			/// <param name="codeGen"></param>
			/// <returns></returns>

			static public string GenerateCodeFromType(CodeTypeDeclaration t,ICodeGenerator codeGen)
			{
				System.IO.StringWriter  w=new System .IO .StringWriter ();
				CodeGeneratorOptions op=new CodeGeneratorOptions ();
				op.BlankLinesBetweenMembers =false;
				op.IndentString ="";
				op.BracingStyle ="Block";
				codeGen .GenerateCodeFromType (t,w,op);
				return w.ToString ();
			}
			static public  string GenerateUsingStatementPattern(string strUsed,ICodeGenerator codeGenerator)
			{
				CodeCompileUnit compUnit=new CodeCompileUnit ();
				System.CodeDom.CodeNamespace nameSpace=new System.CodeDom.CodeNamespace ("NNN");
				compUnit .Namespaces .Add (nameSpace );

				System.IO.StringWriter writer=new System.IO.StringWriter();
			
				codeGenerator.GenerateCodeFromCompileUnit (compUnit,writer,null);
				string [] tokens=Tokenize(writer.ToString ());
			
				writer=new StringWriter();
				CodeNamespaceImport importStatement=new CodeNamespaceImport (strUsed);
				nameSpace.Imports.Add (importStatement);
				codeGenerator.GenerateCodeFromCompileUnit (compUnit,writer,null);
		
				string res=writer.ToString ();
				foreach (string s in tokens)
				{
					if (s!=""||s!=" ")
					{
						int index=res.IndexOf (s);
						res=res.Remove (index,s.Length );
					}
				}
				res=res.Replace ("\n","");
				return res.Trim ();
			}
			static public string[] Tokenize(string s)
			{
				return Regex.Split (s,@"\s+");
			
			}


			/// <summary>
			/// Generates a Class Declartion that can show declaration structure and syntax
			/// so that we can extract class declaration text pattern
			/// </summary>
			/// <param name="t"></param>
			static public void CreateClassToBuildClassTextPattern(out CodeTypeDeclaration t)
			{
				t=new CodeTypeDeclaration ("theclass");
				t.IsClass =true;
				t.TypeAttributes=0;
				t.BaseTypes.Add ( "bases");
				t.Members .Add (new CodeSnippetTypeMember ("body"));
				/*CodeMemberField cmf1 = new CodeMemberField(typeof(string),"m_Name");
				cmf1.Attributes =    MemberAttributes.Private|MemberAttributes.Const |MemberAttributes.Static ;				
				CodeMemberField cmf2 = new CodeMemberField(typeof(int),"m_Age");
				cmf1.Attributes =    MemberAttributes.Public|MemberAttributes.Final ;				
				CodeMemberField cmf3 = new CodeMemberField(typeof(bool),"m_Flag");
				cmf1.Attributes =    MemberAttributes.Public|MemberAttributes.Final ;				
				t.Members .Add (cmf1);
				t.Members .Add (cmf2);
				t.Members .Add (cmf3);

				CodeMemberMethod cmm1=new CodeMemberMethod ();
				cmm1.Name ="method1";
				cmm1.Attributes  =MemberAttributes .Abstract |MemberAttributes.Private;
				cmm1.ReturnType = new CodeTypeReference (typeof(int));
				cmm1.Statements .Add (new CodeMethodReturnStatement (new CodeVariableReferenceExpression ("m_Age")));

				CodeMemberMethod cmm2=new CodeMemberMethod ();
				cmm1.Name ="method2";
				cmm1.Attributes  =MemberAttributes .Overloaded  |MemberAttributes.Private;
				cmm1.ReturnType = new CodeTypeReference (typeof(string));
				cmm1.Statements .Add (new CodeMethodReturnStatement (new CodeVariableReferenceExpression ("m_Name")));

				CodeMemberMethod cmm3=new CodeMemberMethod ();
				cmm1.Name ="method2";
				cmm1.Attributes  =MemberAttributes .Overloaded  |MemberAttributes.Private;
				cmm1.ReturnType = new CodeTypeReference (typeof (int));
				cmm1.Statements .Add (new CodeMethodReturnStatement (new CodeVariableReferenceExpression ("m_Age")));

				CodeMemberMethod cmm4=new CodeMemberMethod ();
				cmm1.Name ="method3";
				cmm1.Attributes  =MemberAttributes .Override |MemberAttributes.Private;
				cmm1.ReturnType = new CodeTypeReference (typeof(bool));
				cmm1.Statements .Add (new CodeMethodReturnStatement (new CodeVariableReferenceExpression ("m_Flag")));
			
				t.Members .Add (new CodeSnippetTypeMember ("body"));*/
				//CodeTypeConstructor  CodeEntryPointMethod cmm1.CustomAttributes .Add (		
			}
	
	
			/// <summary>
			/// Returns the base classes text pattern ex : <code>(?<bases>(\w|\s)*)</code>.
			/// </summary>
			static public string PrepareBasesPattern (ICodeGenerator codeGen)
			{
				CodeTypeDeclaration t;
				CreateClassToBuildClassTextPattern(out t);
				StringBuilder strPattern=new StringBuilder(GenerateCodeFromType(t,codeGen));
			
				string []arr={"bases","body"};
				int minIndex=strPattern.Length ;
				for (int i=0;i<arr.Length -1;i++)
				{
					int index1=strPattern.ToString ().IndexOf (arr[i]);
				
					for (int j=0;j<arr.Length ;j++)
					{
						if (i!=j)
						{
							int index2=strPattern.ToString ().IndexOf (arr[j]);
							if (index2>index1)
								if (index2<minIndex)
									minIndex=index2;
						}
					}
					//get the string between the original parts
					string between=strPattern.ToString ().Substring (index1+arr[i].Length,minIndex-(index1+arr[i].Length ));
					string delimeters="";
					foreach(string s in Regex.Split (between,@"[\s]+"))
					{
						if (s.Length ==1)
							delimeters+=s;
						//else
						//	keywords 
					}
					if (delimeters=="")
					{
						string implementKeyword=LanguageEngine .KeywordInClassImplementInterface (codeGen);
						string inheritKeyword=LanguageEngine .KeywordInClassInheritClass  (codeGen);
						//ooms= one or more space		
						//							 inherit ooms elclass ooms implement 		ooms elinterface 				
					//	arr[i]=@"(?<"+arr[i]+@">(("+ inheritKeyword+@"\s+\w+\s+"+implementKeyword +@"\s+\w+(?:\s*,\s*\w+\s*)*)|("+implementKeyword +@"\s+\w+(?:\s*,\s*\w+\s*)*)|("+inheritKeyword +@"\s+\w+(?:\s*,\s*\w+\s*)*)))";
							arr[i]=@"(?<"+arr[i]+@">(("+ inheritKeyword+@"\s+(\w|[.])+\s+"+implementKeyword +@"\s+(\w|[.])+(?:\s*,\s*\w+\s*)*)|("+implementKeyword +@"\s+(\w|[.])+(?:\s*,\s*\w+\s*)*)|("+inheritKeyword +@"\s+(\w|[.])+(?:\s*,\s*\w+\s*)*)))";
					}
					else
						arr[i]=@"(?<"+arr[i]+">([^"+delimeters+"])($$))";
					//doesn't contain a delimiter that separates
					//between parts of the class
				
				}
				return arr[0];
			}

		}
	}
}